const fs = require('fs');
const SparkMD5 = require('spark-md5');
const log = require('electron-log');
const Http = require('./http.js');
const Store = require('electron-store');
const getUserDataPath = require('./getUserDataPath');
const fetch = require('node-fetch');
const configManager = require('./config');

const http = new Http();
const store = new Store({
    name: 'sync',
    cwd: getUserDataPath(),
});

const user = store.get('user');

const POWERCODE = 14;

class minioFileUpload {
    constructor({ fileSize, fileName, filePath, dirPath, busId, updateId }) {
        console.log(arguments);
        this.fileName = fileName;
        this.busId = busId;
        this.fileSize = fileSize;
        this.filePath = filePath;
        this.dirPath = dirPath;
        this.updateId = updateId;
    }
    async uploads() {
        console.log(this.filePath);
        return new Promise(async(resolve, reject) => {
            if (this.fileSize) {
                let hasPower = await this.checkPower();
                if (hasPower) {
                    try {
                        await this.getFileMD5();
                        let fileKey = await this.checkFileExit();
                        if (fileKey) {
                            log.info('秒传文件，直接上传');
                            this.uploadKey = fileKey;
                            let detail = await this.doAddNode();
                            resolve(detail);
                        } else {
                            await this.uploadMinio(this.uploadKey);
                            let detail = await this.doAddNode();
                            resolve(detail);
                        }
                    } catch {
                        // 写入上传失败的列表
                        log.info('上传失败');
                        resolve({
                            executeStatus: 4,
                        });
                    }
                } else {
                    resolve({
                        executeStatus: 5,
                    });
                }
            } else {
                log.info('空文件限制' + this.fileName);
                resolve({
                    executeStatus: 4,
                });
            }
        });
    }

    checkPower() {
        return new Promise(async(resolve) => {
            const data = {
                busId: this.busId,
                busType: 2,
                appId: 500,
                mid: user.mid,
                coId: user.coId,
                dirPath: this.dirPath ?
                    this.dirPath + '/' + this.fileName :
                    this.fileName,
            };

            const res = await http.request('POST', '/bimfile/doc/findDocPower', data);

            let code = res.data.powerCode;
            log.info(this.fileName + 'code:' + code);
            resolve(code >= POWERCODE);
        });
    }

    async getFileMD5() {
        const that = this;
        return new Promise((resolve) => {
            function readFileSlice(filePath, start, end) {
                return new Promise((resolve, reject) => {
                    const fileStream = fs.createReadStream(filePath, { start, end });
                    const chunks = [];

                    fileStream.on('data', (chunk) => {
                        chunks.push(chunk);
                    });

                    fileStream.on('end', () => {
                        const buffer = Buffer.concat(chunks);
                        resolve(buffer);
                    });

                    fileStream.on('error', (error) => {
                        reject(error);
                    });
                });
            }

            async function calculateFileMD5(filePath) {
                const chunkSize = 1024 * 1024; // 每次读取1MB数据
                let offset = 0;
                const spark = new SparkMD5.ArrayBuffer();

                try {
                    while (true) {
                        const start = offset;
                        const end = offset + chunkSize - 1;

                        const buffer = await readFileSlice(filePath, start, end);
                        if (buffer.length === 0) {
                            break; // 文件已读完
                        }

                        const arrayBuffer = buffer.buffer;
                        spark.append(arrayBuffer);

                        offset += chunkSize;
                    }

                    const md5Hash = spark.end();
                    that.md5 = md5Hash;
                    resolve();
                    console.log('MD5 Hash:', md5Hash);
                } catch (error) {
                    console.error('Error:', error);
                }
            }

            calculateFileMD5(this.filePath);
        });
    }

    getFileSize() {
        const stats = fs.statSync(this.filePath);
        return stats.size;
    }

    doAddNode = () => {
        return new Promise(async(resolve) => {
            let data = [{
                busType: 2,
                busId: this.busId,
                appId: 500,
                source: 5,
                userName: user.mName,
                parentId: '',
                filekey: this.uploadKey,
                fileSize: this.fileSize,
                md5: this.md5,
                name: this.fileName,
                dirPath: this.dirPath ?
                    this.dirPath + '/' + this.fileName :
                    this.fileName,
                nodeId: this.updateId,
                mainId: store.get('mainId')
            }, ];
            const res = await http.request('POST', '/bimfile/doc/create-pc', data);
            log.info('DOADDNODE成功');

            resolve({
                nodeId: res.data[0].nodeId,
                fileId: res.data[0].fileId,
                executeStatus: 3,
            });
        });
    };

    checkFileExit() {
        return new Promise(async(resolve) => {
            const data = {
                file: {
                    md5: this.md5,
                    name: this.fileName,
                    fileSize: this.fileSize,
                },
                busId: this.busId,
                busType: 2,
                appId: 500,
            };

            const res = await http.request('POST', '/bimfile/doc/fastUpload', data);
            this.uploadKey = res.data.uploadKey;
            console.log('获取了fileKey', res);
            resolve(res.data.fileKey);
        });
    }

    getChunkUrl(uploadKey, part) {
        return new Promise(async(resolve) => {
            const data = {
                fileKey: uploadKey,
                chunkSize: part,
            };
            const res = await http.request(
                'POST',
                '/bimfile/minio/createMultipartUpload',
                data
            );
            resolve(res.data);
        });
    }

    minioUpPart(chunkData, chunkUrl, part, i, resolve) {
        return new Promise(async() => {
            let result = await fetch(chunkUrl[i], {
                method: 'PUT',
                body: chunkData[i],
            });

            console.log('上传切片', i, result);

            if (result.status === 200) {
                if (i < part - 1) {
                    i++;
                    await this.minioUpPart(chunkData, chunkUrl, part, i, resolve);
                    console.log('上传切片成功', i);
                } else {
                    // 合并分片
                    let data = {
                        fileKey: this.uploadKey,
                        uploadId: this.uploadId,
                    };
                    const res = await http.request(
                        'POST',
                        '/bimfile/minio/completeMultipartUpload',
                        data
                    );
                    console.log('合并切片数据', data);
                    console.log('合并切片成功', res);
                    log.info('切片minio上传成功');
                    resolve('success');

                    // if (res.success) {
                    // }
                }
            }
        });
    }

    async uploadMinio(uploadKey) {
        return new Promise(async(resolve) => {
            fs.readFile(this.filePath, async(err, data) => {
                const chunkSize = 5 * 1024 * 1024; // 每次读取1MB数据
                const fileSize = data.length;
                let start = 0;
                let end = chunkSize;
                const part = Math.ceil(fileSize / chunkSize);

                const fileChunks = [];
                while (start < fileSize) {
                    const chunk = data.slice(start, end);
                    fileChunks.push(chunk);

                    start = end;
                    end += chunkSize;
                }

                const chunkListData = await this.getChunkUrl(uploadKey, part);
                this.uploadId = chunkListData.uploadId;
                const chunkList = chunkListData.chunkList;

                console.log('uploadId', this.uploadId);
                console.log('总切片', part);
                let res = await this.minioUpPart(
                    fileChunks,
                    chunkList,
                    part,
                    0,
                    resolve
                );
            });
        });
    }
}

module.exports = minioFileUpload;